{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# CONVOLUTIONAL NEURAL NETWORK WITH CUSTOM DATA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Packages loaded\n"
     ]
    }
   ],
   "source": [
    "import os\n",
    "import numpy as np\n",
    "import tensorflow as tf\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline  \n",
    "print (\"Packages loaded\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# LOAD DATA"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "['trainlabel', 'imgsize', 'trainimg', 'testimg', 'testlabel', 'use_gray']\n",
      "408 train images loaded\n",
      "273 test images loaded\n",
      "4096 dimensional input\n",
      "Image size is [64 64]\n",
      "4 classes\n"
     ]
    }
   ],
   "source": [
    "# Load them!\n",
    "cwd = os.getcwd()\n",
    "loadpath = cwd + \"/data/custom_data.npz\"\n",
    "l = np.load(loadpath)\n",
    "\n",
    "# See what's in here\n",
    "print (l.files)\n",
    "\n",
    "# Parse data\n",
    "trainimg = l['trainimg']\n",
    "trainlabel = l['trainlabel']\n",
    "testimg = l['testimg']\n",
    "testlabel = l['testlabel']\n",
    "imgsize = l['imgsize']\n",
    "use_gray = l['use_gray']\n",
    "ntrain = trainimg.shape[0]\n",
    "nclass = trainlabel.shape[1]\n",
    "dim    = trainimg.shape[1]\n",
    "ntest  = testimg.shape[0]\n",
    "print (\"%d train images loaded\" % (ntrain))\n",
    "print (\"%d test images loaded\" % (ntest))\n",
    "print (\"%d dimensional input\" % (dim))\n",
    "print (\"Image size is %s\" % (imgsize))\n",
    "print (\"%d classes\" % (nclass))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# DEFINE NETWORK"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "tf.set_random_seed(0)\n",
    "n_input  = dim\n",
    "n_output = nclass\n",
    "if use_gray:\n",
    "    weights  = {\n",
    "        'wc1': tf.Variable(tf.random_normal([5, 5, 1, 128], stddev=0.1)),\n",
    "        'wc2': tf.Variable(tf.random_normal([5, 5, 128, 128], stddev=0.1)),\n",
    "        'wd1': tf.Variable(tf.random_normal(\n",
    "                [(int)(imgsize[0]/4*imgsize[1]/4)*128, 128], stddev=0.1)),\n",
    "        'wd2': tf.Variable(tf.random_normal([128, n_output], stddev=0.1))\n",
    "    }\n",
    "else:\n",
    "    weights  = {\n",
    "        'wc1': tf.Variable(tf.random_normal([5, 5, 3, 128], stddev=0.1)),\n",
    "        'wc2': tf.Variable(tf.random_normal([5, 5, 128, 128], stddev=0.1)),\n",
    "        'wd1': tf.Variable(tf.random_normal(\n",
    "                [(int)(imgsize[0]/4*imgsize[1]/4)*128, 128], stddev=0.1)),\n",
    "        'wd2': tf.Variable(tf.random_normal([128, n_output], stddev=0.1))\n",
    "    }\n",
    "biases   = {\n",
    "    'bc1': tf.Variable(tf.random_normal([128], stddev=0.1)),\n",
    "    'bc2': tf.Variable(tf.random_normal([128], stddev=0.1)),\n",
    "    'bd1': tf.Variable(tf.random_normal([128], stddev=0.1)),\n",
    "    'bd2': tf.Variable(tf.random_normal([n_output], stddev=0.1))\n",
    "}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "NETWORK READY\n"
     ]
    }
   ],
   "source": [
    "def conv_basic(_input, _w, _b, _keepratio, _use_gray):\n",
    "    # INPUT\n",
    "    if _use_gray:\n",
    "        _input_r = tf.reshape(_input, shape=[-1, imgsize[0], imgsize[1], 1])\n",
    "    else:\n",
    "        _input_r = tf.reshape(_input, shape=[-1, imgsize[0], imgsize[1], 3])\n",
    "    # CONVOLUTION LAYER 1\n",
    "    _conv1 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(_input_r\n",
    "        , _w['wc1'], strides=[1, 1, 1, 1], padding='SAME'), _b['bc1']))\n",
    "    _pool1 = tf.nn.max_pool(_conv1, ksize=[1, 2, 2, 1]\n",
    "        , strides=[1, 2, 2, 1], padding='SAME')\n",
    "    _pool_dr1 = tf.nn.dropout(_pool1, _keepratio)\n",
    "    # CONVOLUTION LAYER 2\n",
    "    _conv2 = tf.nn.relu(tf.nn.bias_add(tf.nn.conv2d(_pool_dr1\n",
    "        , _w['wc2'], strides=[1, 1, 1, 1], padding='SAME'), _b['bc2']))\n",
    "    _pool2 = tf.nn.max_pool(_conv2, ksize=[1, 2, 2, 1]\n",
    "        , strides=[1, 2, 2, 1], padding='SAME')\n",
    "    _pool_dr2 = tf.nn.dropout(_pool2, _keepratio)\n",
    "    # VECTORIZE\n",
    "    _dense1 = tf.reshape(_pool_dr2\n",
    "                         , [-1, _w['wd1'].get_shape().as_list()[0]])\n",
    "    # FULLY CONNECTED LAYER 1\n",
    "    _fc1 = tf.nn.relu(tf.add(tf.matmul(_dense1, _w['wd1']), _b['bd1']))\n",
    "    _fc_dr1 = tf.nn.dropout(_fc1, _keepratio)\n",
    "    # FULLY CONNECTED LAYER 2\n",
    "    _out = tf.add(tf.matmul(_fc_dr1, _w['wd2']), _b['bd2'])\n",
    "    # RETURN\n",
    "    out = {\n",
    "        'input_r': _input_r, 'conv1': _conv1, 'pool1': _pool1\n",
    "        , 'pool1_dr1': _pool_dr1, 'conv2': _conv2, 'pool2': _pool2\n",
    "        , 'pool_dr2': _pool_dr2, 'dense1': _dense1, 'fc1': _fc1\n",
    "        , 'fc_dr1': _fc_dr1, 'out': _out\n",
    "    }\n",
    "    return out\n",
    "print (\"NETWORK READY\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# DEFINE FUNCTIONS"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "FUNCTIONS READY\n"
     ]
    }
   ],
   "source": [
    "# tf Graph input\n",
    "x = tf.placeholder(tf.float32, [None, n_input])\n",
    "y = tf.placeholder(tf.float32, [None, n_output])\n",
    "keepratio = tf.placeholder(tf.float32)\n",
    "\n",
    "# Functions! \n",
    "_pred = conv_basic(x, weights, biases, keepratio, use_gray)['out']\n",
    "cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(_pred, y))\n",
    "WEIGHT_DECAY_FACTOR = 0.0001\n",
    "l2_loss = tf.add_n([tf.nn.l2_loss(v) \n",
    "            for v in tf.trainable_variables()])\n",
    "cost = cost + WEIGHT_DECAY_FACTOR*l2_loss\n",
    "optm = tf.train.AdamOptimizer(learning_rate=0.001).minimize(cost)\n",
    "_corr = tf.equal(tf.argmax(_pred,1), tf.argmax(y,1)) # Count corrects\n",
    "accr = tf.reduce_mean(tf.cast(_corr, tf.float32)) # Accuracy\n",
    "init = tf.initialize_all_variables()\n",
    "print (\"FUNCTIONS READY\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# OPTIMIZE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch: 000/400 cost: 10.054866600\n",
      " Training accuracy: 0.750\n",
      " Test accuracy: 0.755\n",
      "Epoch: 040/400 cost: 2.086551237\n",
      " Training accuracy: 0.980\n",
      " Test accuracy: 0.901\n",
      "Epoch: 080/400 cost: 1.829108810\n",
      " Training accuracy: 1.000\n",
      " Test accuracy: 0.930\n"
     ]
    }
   ],
   "source": [
    "# Parameters\n",
    "training_epochs = 400\n",
    "batch_size      = 100\n",
    "display_step    = 40\n",
    "\n",
    "# Launch the graph\n",
    "sess = tf.Session()\n",
    "sess.run(init)\n",
    "\n",
    "# Training cycle\n",
    "for epoch in range(training_epochs):\n",
    "    avg_cost = 0.\n",
    "    num_batch = int(ntrain/batch_size)+1\n",
    "    # Loop over all batches\n",
    "    for i in range(num_batch): \n",
    "        randidx = np.random.randint(ntrain, size=batch_size)\n",
    "        batch_xs = trainimg[randidx, :]\n",
    "        batch_ys = trainlabel[randidx, :]                \n",
    "        # Fit training using batch data\n",
    "        sess.run(optm, feed_dict={x: batch_xs, y: batch_ys\n",
    "                                  , keepratio:0.7})\n",
    "        # Compute average loss\n",
    "        avg_cost += sess.run(cost, feed_dict={x: batch_xs, y: batch_ys\n",
    "                                , keepratio:1.})/num_batch\n",
    "\n",
    "    # Display logs per epoch step\n",
    "    if epoch % display_step == 0 or epoch == training_epochs-1:\n",
    "        print (\"Epoch: %03d/%03d cost: %.9f\" % \n",
    "               (epoch, training_epochs, avg_cost))\n",
    "        train_acc = sess.run(accr, feed_dict={x: batch_xs\n",
    "                                , y: batch_ys, keepratio:1.})\n",
    "        print (\" Training accuracy: %.3f\" % (train_acc))\n",
    "        test_acc = sess.run(accr, feed_dict={x: testimg\n",
    "                                , y: testlabel, keepratio:1.})\n",
    "        print (\" Test accuracy: %.3f\" % (test_acc))\n",
    "print (\"Optimization Finished!\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "collapsed": false
   },
   "source": [
    "# CLOSE SESSION"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "sess.close()\n",
    "print (\"Session closed.\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
